<h2>Why is this an issue?</h2>
<p>Looking for a given substring starting from a specified offset can be achieved by such code: <code>str.substring(beginIndex).indexOf(char1)</code>.
This works well, but it creates a new <code>String</code> for each call to the <code>substring</code> method. When this is done in a loop, a lot of
<code>Strings</code> are created for nothing, which can lead to performance problems if <code>str</code> is large.</p>
<p>To avoid performance problems, <code>String.substring(beginIndex)</code> should not be chained with the following methods:</p>
<ul>
  <li> <code>indexOf(int ch)</code> </li>
  <li> <code>indexOf(String str)</code> </li>
  <li> <code>lastIndexOf(int ch)</code> </li>
  <li> <code>lastIndexOf(String str)</code> </li>
  <li> <code>startsWith(String prefix)</code> </li>
</ul>
<p>For each of these methods, another method with an additional parameter is available to specify an offset.</p>
<p>Using these methods will avoid the creation of additional <code>String</code> instances. For indexOf methods, adjust the returned value by
subtracting the substring index parameter to obtain the same result.</p>
<h3>Noncompliant code example</h3>
<pre>
str.substring(beginIndex).indexOf(char1); // Noncompliant; a new String is going to be created by "substring"
</pre>
<h3>Compliant solution</h3>
<pre>
str.indexOf(char1, beginIndex) - beginIndex; // index for char1 not found is (-1-beginIndex)
</pre>
<h2>Resources</h2>
<h3>Benchmarks</h3>
<table>
  <colgroup>
    <col style="width: 20%;">
    <col style="width: 20%;">
    <col style="width: 20%;">
    <col style="width: 20%;">
    <col style="width: 20%;">
  </colgroup>
  <thead>
    <tr>
      <th>Method</th>
      <th>stringSize</th>
      <th>Runtime</th>
      <th>Average time</th>
      <th>Error margin</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><p>indexOfOnly</p></td>
      <td><p>10</p></td>
      <td><p>Temurin 21</p></td>
      <td><p>1.55 ns/op</p></td>
      <td><p>±0.12 ns/op</p></td>
    </tr>
    <tr>
      <td><p>indexOfOnly</p></td>
      <td><p>100</p></td>
      <td><p>Temurin 21</p></td>
      <td><p>1.78 ns/op</p></td>
      <td><p>±0.05 ns/op</p></td>
    </tr>
    <tr>
      <td><p>indexOfOnly</p></td>
      <td><p>1000</p></td>
      <td><p>Temurin 21</p></td>
      <td><p>1.82 ns/op</p></td>
      <td><p>±0.18 ns/op</p></td>
    </tr>
    <tr>
      <td><p>indexOfOnly</p></td>
      <td><p>10000</p></td>
      <td><p>Temurin 21</p></td>
      <td><p>1.77 ns/op</p></td>
      <td><p>±0.08 ns/op</p></td>
    </tr>
    <tr>
      <td><p>substringThenIndexOf</p></td>
      <td><p>10</p></td>
      <td><p>Temurin 21</p></td>
      <td><p>4.85 ns/op</p></td>
      <td><p>±0.41 ns/op</p></td>
    </tr>
    <tr>
      <td><p>substringThenIndexOf</p></td>
      <td><p>100</p></td>
      <td><p>Temurin 21</p></td>
      <td><p>6.22 ns/op</p></td>
      <td><p>±0.40 ns/op</p></td>
    </tr>
    <tr>
      <td><p>substringThenIndexOf</p></td>
      <td><p>1000</p></td>
      <td><p>Temurin 21</p></td>
      <td><p>14.22 ns/op</p></td>
      <td><p>±1.66 ns/op</p></td>
    </tr>
    <tr>
      <td><p>substringThenIndexOf</p></td>
      <td><p>10000</p></td>
      <td><p>Temurin 21</p></td>
      <td><p>275.00 ns/op</p></td>
      <td><p>±20.49 ns/op</p></td>
    </tr>
  </tbody>
</table>
<p><strong>Benchmarking code</strong></p>
<p>The results were generated by running the following snippet with <a href="https://github.com/openjdk/jmh">JMH</a>.</p>
<pre>
@BenchmarkMode({Mode.AverageTime})
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
public class S4635 {
  @Param({"10", "100", "1000", "10000"})
  int stringSize;

  String input;

  @Setup
  public void setup() {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i &lt; stringSize; i++) {
      builder.append('a');
    }
    input = builder.toString();
  }

  @Benchmark
  public int substringThenIndexOf() {
    return stringSize / 2 + input.substring(stringSize / 2).indexOf('a');
  }

  @Benchmark
  public int indexOfOnly() {
    return input.indexOf('a', stringSize / 2);
  }
}
</pre>

